package com.sourceQ.system.service.tenant.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sourceQ.common.core.constant.dict.BmDelFlag;
import com.sourceQ.common.core.constant.dict.BmTenantPackageStatus;
import com.sourceQ.common.core.utils.DateUtils;
import com.sourceQ.common.core.utils.RandomUtils;
import com.sourceQ.common.core.utils.SpellUtils;
import com.sourceQ.common.core.utils.StringUtils;
import com.sourceQ.common.core.utils.bean.BeanUtils;
import com.sourceQ.common.security.utils.SecurityUtils;
import com.sourceQ.system.api.domain.SysDept;
import com.sourceQ.system.api.domain.SysUser;
import com.sourceQ.system.domain.tenant.Tenant;
import com.sourceQ.system.vo.tenant.TenantPackageRespVO;
import com.sourceQ.system.dto.tenant.TenantPageReqDTO;
import com.sourceQ.system.dto.tenant.TenantSaveReqDTO;
import com.sourceQ.system.vo.tenant.TenantVo;
import com.sourceQ.system.mapper.tenant.TenantMapper;
import com.sourceQ.system.service.dept.ISysDeptService;
import com.sourceQ.system.service.handler.TenantInfoHandler;
import com.sourceQ.system.service.handler.TenantMenuHandler;
import com.sourceQ.system.service.role.ISysRoleService;
import com.sourceQ.system.service.tenant.TenantPackageService;
import com.sourceQ.system.service.tenant.TenantService;
import com.sourceQ.system.service.user.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import static com.sourceQ.common.core.constant.ErrorCodeConstants.*;
import static com.sourceQ.common.core.utils.ExceptionUtil.exception;

/**
 * @author: SourceQ
 * @create: 2024-03-26 11:09
 * @Description:
 */
@Service
@Validated
public class TenantServiceImpl extends ServiceImpl<TenantMapper,Tenant> implements TenantService {

    @Autowired
    private ISysUserService userService;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    @Lazy
    private TenantPackageService tenantPackageService;
    @Autowired
    private ISysRoleService roleService;
    @Override
    @Transactional
    public Map<String, String> createTenant(TenantSaveReqDTO createReqVO) {
        //校验名称是否重复，域名是否重复，套餐是否存在
        if (!validTenantNameDuplicate(createReqVO.getName())){
            throw exception(TENANT_NAME_DUPLICATE,createReqVO.getName());
        }
        if (!validTenantWebsiteDuplicate(createReqVO.getWebsite())){
            throw exception(TENANT_WEBSITE_DUPLICATE,createReqVO.getWebsite());
        }
        tenantPackageService.validTenantPackage(createReqVO.getPackageId());
        //创建租户的时候，需要为其创建一个默认管理员角色，该角色拥有该租户所选套餐的全部角色，同时生成注册码供该租户的其他用户做账号注册。
        Tenant tenant = new Tenant();
        BeanUtils.copyProperties(createReqVO,tenant);
        //生成注册码
        tenant.setRegisterCode(RandomUtils.generateRandomString(10));
        baseMapper.insert(tenant);
        Map<String, String> map = buildTenantInit(tenant, createReqVO);
        return map;
    }

    @Override
    public void updateTenant(TenantSaveReqDTO updateReqVO) {
        //租户修改套餐时，需对应修改租户的用户所拥有的角色
        //修改用户
    }

    @Override
    public void updateTenantUserRole(Long tenantId, Set<Long> roleIds) {

    }

    @Override
    public void deleteTenant(Long[] ids) {
        for (Long id : ids) {
            Tenant tenant = validateUpdateTenant(id);
            if (isSystemTenant(tenant)) {
                throw exception(TENANT_CAN_NOT_UPDATE_SYSTEM);
            }
            if (!DateUtils.isExpired(tenant.getExpireTime())){
                throw exception(TENANT_UN_EXPIRE);
            }
            baseMapper.deleteById(tenant);
        }

    }

    @Override
    public TenantVo getTenant(Long id) {
        TenantVo vo = new TenantVo();
        Tenant tenant = baseMapper.selectById(id);
        BeanUtils.copyProperties(tenant,vo);
        vo.setTenantPackage(tenantPackageService.getTenantPackage(tenant.getPackageId()));
        return vo;
    }

    @Override
    public IPage<TenantVo> getTenantPage(Page page, TenantPageReqDTO pageReqVO) {
        return baseMapper.page(page,pageReqVO);
    }

    @Override
    public Tenant getTenantByName(String name) {
        return null;
    }

    @Override
    public Long getTenantCountByPackageId(Long packageId) {
        return baseMapper.selectCountByPackageId(packageId);
    }

    @Override
    public List<Tenant> getTenantListByPackageId(Long packageId) {
        return null;
    }

    @Override
    public void handleTenantInfo(TenantInfoHandler handler) {

    }

    @Override
    public void handleTenantMenu(TenantMenuHandler handler) {

    }

    @Override
    public List<Long> getTenantIdList() {
        List<Tenant> tenants = baseMapper.searchAllByDelFlagTenants();
        return CollectionUtils.isEmpty(tenants) ? Collections.EMPTY_LIST:tenants.stream().map(Tenant::getId).collect(Collectors.toList());
    }

    @Override
    public void validTenant(Long id) {
        Tenant tenant = baseMapper.selectById(id);
        if (tenant == null) {
            throw exception(TENANT_NOT_EXISTS);
        }
        if (BmTenantPackageStatus.STOP.equals(tenant.getStatus())) {
            throw exception(TENANT_DISABLE,tenant.getName());
        }
        if (DateUtils.isExpired(tenant.getExpireTime())){
            throw exception(TENANT_EXPIRE, tenant.getName());
        }
    }

    @Override
    public void changeStatus(Long id, String status) {
        Tenant tenant = validateUpdateTenant(id);
        if (StringUtils.isEmpty(status)||StringUtils.containsAny(Lists.newArrayList("0","1"),status)){
            throw exception(PARAMETER_ERROR,status);
        }
        tenant.setStatus(status);
        baseMapper.updateById(tenant);
    }

    /**
     * 租户数据校验
     * @param id
     * @return
     */
    private Tenant validateUpdateTenant(Long id){
        Tenant tenant = baseMapper.selectById(id);
        if (tenant == null) {
            throw exception(TENANT_NOT_EXISTS);
        }
        return tenant;
    }

    /**
     * 是否是系统管理员
     * @param tenant
     * @return
     */
    private static boolean isSystemTenant(Tenant tenant) {
        return Objects.equals(tenant.getPackageId(), Tenant.PACKAGE_ID_SYSTEM);
    }

    /**
     * 校验租户名称是否存在
     * @param name
     */
    private boolean validTenantNameDuplicate(String name){
        Tenant tenant = baseMapper.selectOne(new LambdaQueryWrapper<Tenant>().eq(Tenant::getName, name));
        return tenant==null;
    }

    /**
     * 校验域名是否存在
     * @param website
     * @return
     */
    private boolean validTenantWebsiteDuplicate(String website){
        return baseMapper.selectOne(new LambdaQueryWrapper<Tenant>().eq(Tenant::getWebsite,website))==null;
    }

    /**
     * 租户初始化
     * @param tenant
     * @deprecated 部门（公司）表，用户表，用户角色关联表
     * @return 初始化的用户名和登录密码
     */
    @Transactional
    public Map<String,String> buildTenantInit(Tenant tenant, TenantSaveReqDTO createReqVO){
        Map<String,String> result = Maps.newHashMap();
        SysDept sysDept = new SysDept();
        sysDept.setParentId(0L);
        sysDept.setDelFlag(BmDelFlag.EXIST);
        sysDept.setAncestors("0");
        sysDept.setDeptName(tenant.getName());
        sysDept.setOrderNum(0);
        sysDept.setLeader(tenant.getContactName());
        sysDept.setPhone(tenant.getContactMobile());
        sysDept.setEmail(createReqVO.getEmail());
        sysDept.setStatus("0");
        sysDept.setTenantId(tenant.getId());
        deptService.insertDept(sysDept);
        SysUser user = new SysUser();
        user.setDelFlag(BmDelFlag.EXIST);
        user.setTenantId(tenant.getId());
        String userName = SpellUtils.getENameAbbr(tenant.getName());
        user.setUserName(userName);//中文转拼音缩写
        //user.setAvatar();
        user.setDeptId(sysDept.getDeptId());
        user.setNickName(tenant.getName());
        user.setEmail(createReqVO.getEmail());
        user.setPhonenumber(tenant.getContactMobile());
        String password = userName.length()>6?userName:userName+RandomUtils.generateRandomString(6-userName.length());
        user.setPassword(SecurityUtils.encryptPassword(password));
        user.setSex(createReqVO.getSex());
        user.setStatus("0");
        //角色
        TenantPackageRespVO tenantPackage = tenantPackageService.getTenantPackage(createReqVO.getPackageId());
        user.setRoleIds(tenantPackage.getRoleIds().toArray(new Long[tenantPackage.getRoleIds().size()]));
        //TODO 需加一个部门和角色的关联
        roleService.insertRoleAndDeptRelated(sysDept.getDeptId(),Lists.newArrayList(tenantPackage.getRoleIds()));
        //职位
        //user.setPostIds(createReqVO.getPostIds().toArray(new Long[createReqVO.getPostIds().size()]));
        userService.insertUser(user);
        result.put("tenant",tenant.getName());
        result.put("username",userName);
        result.put("password",password);
        return result;
    }
}
